Add Fréchet Radiomics Distance (FRD) to MONAI metrics (#8643)#8769
Add Fréchet Radiomics Distance (FRD) to MONAI metrics (#8643)#8769AymanL wants to merge 3 commits intoProject-MONAI:devfrom
Conversation
📝 WalkthroughWalkthroughAdds Fréchet Radiomics Distance (FRD) support. New module monai/metrics/frd.py implements a FrechetRadiomicsDistance Metric class and a get_frd_score(y_pred, y) function that compute the Fréchet distance by applying FID logic to radiomic feature vectors (expects 2D tensors (N, F); raises on ndim > 2). monai/metrics/init.py now exports Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
monai/metrics/frd.py (1)
52-65: AddRaisessection to docstring.
get_fid_scoreraisesValueErrorwhen inputs have >2 dimensions. Document this for callers.📝 Suggested docstring addition
Args: y_pred: Feature vectors for the first distribution, shape (N, F). y: Feature vectors for the second distribution, shape (N, F). Returns: Scalar tensor containing the Fréchet Radiomics Distance. + + Raises: + ValueError: If inputs have more than 2 dimensions. """ return get_fid_score(y_pred, y)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@monai/metrics/frd.py` around lines 52 - 65, Add a Raises section to the get_frd_score docstring documenting that get_fid_score may raise a ValueError when inputs have more than 2 dimensions; update the get_frd_score docstring (the function named get_frd_score calling get_fid_score) to include a "Raises" entry that explicitly states ValueError is raised for input tensors with rank > 2 so callers are aware of this precondition.tests/metrics/test_compute_frd_metric.py (1)
41-43: Test name and setup are slightly misleading.The ValueError is raised because
ndimension() > 2, not due to spatial dimension mismatch (144 vs 145). Consider renaming totest_rejects_high_dimensional_inputand using identical tensors.♻️ Suggested clarification
- def test_input_dimensions(self): + def test_rejects_high_dimensional_input(self): + """Inputs with more than 2 dimensions should raise ValueError.""" with self.assertRaises(ValueError): - FrechetRadiomicsDistance()(torch.ones([3, 3, 144, 144]), torch.ones([3, 3, 145, 145])) + FrechetRadiomicsDistance()(torch.ones([3, 3, 144, 144]), torch.ones([3, 3, 144, 144]))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/metrics/test_compute_frd_metric.py` around lines 41 - 43, Rename the test to reflect the actual rejection reason and make the input tensors identical so the failure is due to ndimension()>2: change the test name from test_input_dimensions to test_rejects_high_dimensional_input and call FrechetRadiomicsDistance() with two tensors of the same shape (e.g., torch.ones([3, 3, 144, 144]) for both) so the ValueError arises from the high number of dimensions rather than mismatched spatial sizes; update any test docstring or comment accordingly to reference FrechetRadiomicsDistance and ndimension.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@monai/metrics/frd.py`:
- Around line 52-65: Add a Raises section to the get_frd_score docstring
documenting that get_fid_score may raise a ValueError when inputs have more than
2 dimensions; update the get_frd_score docstring (the function named
get_frd_score calling get_fid_score) to include a "Raises" entry that explicitly
states ValueError is raised for input tensors with rank > 2 so callers are aware
of this precondition.
In `@tests/metrics/test_compute_frd_metric.py`:
- Around line 41-43: Rename the test to reflect the actual rejection reason and
make the input tensors identical so the failure is due to ndimension()>2: change
the test name from test_input_dimensions to test_rejects_high_dimensional_input
and call FrechetRadiomicsDistance() with two tensors of the same shape (e.g.,
torch.ones([3, 3, 144, 144]) for both) so the ValueError arises from the high
number of dimensions rather than mismatched spatial sizes; update any test
docstring or comment accordingly to reference FrechetRadiomicsDistance and
ndimension.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e025c2d5-a892-4a84-a2a7-8546a1f5e587
📒 Files selected for processing (3)
monai/metrics/__init__.pymonai/metrics/frd.pytests/metrics/test_compute_frd_metric.py
Signed-off-by: AymanL <40838419+AymanL@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
monai/metrics/frd.py (1)
24-36: Tighten the API docstring.This callable only accepts pre-extracted
(N, F)feature tensors. Saying it “works for 2D and 3D images” and supports mask conditioning reads like image or mask tensors are accepted here, which this API does not expose. Please state that 2D/3D images and masks are handled during external feature extraction, not by this metric itself.As per coding guidelines, "Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@monai/metrics/frd.py` around lines 24 - 36, Update the frd module/class docstring to explicitly state the callable accepts only pre-extracted feature tensors of shape (N, F) and does not accept raw 2D/3D images or masks; clarify that any handling of 2D/3D images and mask-based conditioning must be performed during external feature extraction (e.g., via PyRadiomics) prior to calling this metric. Tighten wording to remove implications that images or masks are accepted directly, and add Google-style docstring sections for Args (describe the features tensor shape and dtype), Returns (what the function returns), and Raises (any errors for invalid shapes or inputs), referencing the callable name in the docstring so reviewers can locate it easily.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@monai/metrics/frd.py`:
- Around line 52-69: Add a symmetric input-dimension validation in
get_frd_score: check y_pred.ndimension() > 2 and raise the same ValueError used
by monai.metrics.fid.get_fid_score when inputs have >2 dims, before calling
get_fid_score(y_pred, y); also add a unit test that passes a 3D y_pred and a
valid 2D y to exercise the error path. This ensures get_frd_score mirrors
get_fid_score's shape guard and the y_pred-only high-dimensional case is
covered.
---
Nitpick comments:
In `@monai/metrics/frd.py`:
- Around line 24-36: Update the frd module/class docstring to explicitly state
the callable accepts only pre-extracted feature tensors of shape (N, F) and does
not accept raw 2D/3D images or masks; clarify that any handling of 2D/3D images
and mask-based conditioning must be performed during external feature extraction
(e.g., via PyRadiomics) prior to calling this metric. Tighten wording to remove
implications that images or masks are accepted directly, and add Google-style
docstring sections for Args (describe the features tensor shape and dtype),
Returns (what the function returns), and Raises (any errors for invalid shapes
or inputs), referencing the callable name in the docstring so reviewers can
locate it easily.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ab4187ab-ad3b-4657-921a-6464fefb2d3c
📒 Files selected for processing (2)
monai/metrics/frd.pytests/metrics/test_compute_frd_metric.py
…ub.com> I, AymanL <40838419+AymanL@users.noreply.github.com>, hereby add my Signed-off-by to this commit: be31e64 Signed-off-by: AymanL <40838419+AymanL@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
monai/metrics/frd.py (1)
22-49: Clarify the callable API in the docstrings.
FrechetRadiomicsDistance()takes no constructor args, but the class docstring has anArgs:/Returns:block for__call__, and__call__itself is undocumented. Move the parameter/exception docs onto__call__(or keep them only onget_frd_score) and phrase the 2D/3D image + mask support as upstream feature-extraction context, not direct inputs to this class.As per coding guidelines, "Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings."
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@monai/metrics/frd.py`:
- Around line 52-71: The get_frd_score function currently only rejects tensors
with ndimension() > 2 but should enforce a strict (N, F) contract and reject
non-2D inputs and single-sample batches before delegating to get_fid_score;
modify get_frd_score to validate that both y_pred.ndimension() == 2 and
y.ndimension() == 2 and that y_pred.size(0) >= 2 and y.size(0) >= 2, raising a
clear ValueError if any check fails (mentioning expected shape and minimum batch
size), then keep calling get_fid_score when checks pass, and add unit tests that
assert ValueError is raised for 0D/1D inputs and for N < 2 for both y_pred and
y.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a736e1b6-45fd-4ce7-81bf-045e2e26f5f1
📒 Files selected for processing (1)
monai/metrics/frd.py
| def get_frd_score(y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor: | ||
| """Computes the FRD score from two batches of radiomic feature vectors. | ||
|
|
||
| The implementation reuses the same Fréchet distance as FID; only the | ||
| semantics (radiomic features vs. deep features) differ. | ||
|
|
||
| Args: | ||
| y_pred: Feature vectors for the first distribution, shape (N, F). | ||
| y: Feature vectors for the second distribution, shape (N, F). | ||
|
|
||
| Returns: | ||
| Scalar tensor containing the Fréchet Radiomics Distance. | ||
|
|
||
| Raises: | ||
| ValueError: When either tensor has more than 2 dimensions. Inputs must have | ||
| shape (number of samples, number of features). | ||
| """ | ||
| if y_pred.ndimension() > 2 or y.ndimension() > 2: | ||
| raise ValueError("Inputs should have (number images, number of features) shape.") | ||
| return get_fid_score(y_pred, y) |
There was a problem hiding this comment.
Enforce the full (N, F) contract here.
ndimension() > 2 still lets 0D/1D tensors and N < 2 batches fall through into get_fid_score, where covariance estimation is not well-defined and failures get opaque. Please reject non-2D inputs and single-sample batches here, then add tests for both cases.
🩹 Proposed fix
def get_frd_score(y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor:
@@
- if y_pred.ndimension() > 2 or y.ndimension() > 2:
+ if y_pred.ndimension() != 2 or y.ndimension() != 2:
raise ValueError("Inputs should have (number images, number of features) shape.")
+ if y_pred.shape[0] < 2 or y.shape[0] < 2:
+ raise ValueError("At least 2 samples are required to estimate covariance.")
return get_fid_score(y_pred, y)🧰 Tools
🪛 Ruff (0.15.4)
[warning] 70-70: Avoid specifying long messages outside the exception class
(TRY003)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@monai/metrics/frd.py` around lines 52 - 71, The get_frd_score function
currently only rejects tensors with ndimension() > 2 but should enforce a strict
(N, F) contract and reject non-2D inputs and single-sample batches before
delegating to get_fid_score; modify get_frd_score to validate that both
y_pred.ndimension() == 2 and y.ndimension() == 2 and that y_pred.size(0) >= 2
and y.size(0) >= 2, raising a clear ValueError if any check fails (mentioning
expected shape and minimum batch size), then keep calling get_fid_score when
checks pass, and add unit tests that assert ValueError is raised for 0D/1D
inputs and for N < 2 for both y_pred and y.
Fixes #8643
Description
Implements FRD as in Konz et al. (arXiv:2412.01496): same Fréchet distance formula as FID, applied to pre-extracted radiomic features.
Supports 2D/3D and optional mask conditioning via external feature extraction (e.g. PyRadiomics).
Types of changes
./runtests.sh -f -u --net --coverage../runtests.sh --quick --unittests --disttests.make htmlcommand in thedocs/folder.